#include "cuda_device.cuh"
#include <cuda_runtime_api.h>

namespace gc {
	void MCudaDevice::calcBlockSize(int *minGridSize, int *optBlockSize, void(*func), int smem, int numThread) {
		cudaOccupancyMaxPotentialBlockSize(minGridSize, optBlockSize, func, smem, numThread);
	}

	std::pair<int, int> MCudaDevice::getOptLaunchParams(int numThread, unsigned int smemItemSize, void(*func)) {
		int gridSize, bs;
		if (smemItemSize == 0) {
			int minGridSize, optBlockSize;
			cudaOccupancyMaxPotentialBlockSize(&minGridSize, &optBlockSize, func, 0, numThread);
			bs = optBlockSize;
			gridSize = (numThread + bs - 1) / bs;
		}
		else {
			// blocksize constrained by available shared memory
			unsigned int smemPerBlock = 512 * smemItemSize;
			if (smemPerBlock > prop.sharedMemPerBlock) smemPerBlock = prop.sharedMemPerBlock;
			int minGridSize, optBlockSize;
			cudaOccupancyMaxPotentialBlockSize(&minGridSize, &optBlockSize, func, smemPerBlock, numThread);
			bs = dtNextPow2(optBlockSize);
			gridSize = (numThread + bs - 1) / bs;
			if ((bs > optBlockSize && gridSize != 1) || (bs*smemItemSize > prop.sharedMemPerBlock)) {
				bs >>= 1;
				gridSize = (numThread + bs - 1) / bs;
			}
		}
		return std::pair<int, int>(gridSize, bs);
	}
}